window.addEventListener('load', () => {
    const table = document.querySelector("table");
    // 小旗的字体图标
    const flag_html = `<svg class="icon" aria-hidden="true">
                                    <use xlink:href="#icon-qizi"></use>
                                 </svg>`;
    // 炸弹的字体图标 有 icon-zhadan icon-Bomb 和 icon-Bomb1 可选
    const bomb_html = `<svg class="icon" aria-hidden="true">
                                    <use xlink:href="#icon-Bomb"></use>
                                 </svg>`;
    // 页面打开时候初始化
    for (let i = 0; i < 10; i++) {
        let tr = document.createElement("tr");
        for (let j = 0; j < 10; j++) {
            let td = document.createElement("td");
            td.classList.add("cube");
            tr.appendChild(td);
        }
        table.appendChild(tr);
    }
    //开始游戏函数
    function create(n, bombNum) {
        let rest = document.querySelector(".bombinfo span");
        rest.innerHTML = `剩余旗子数：${bombNum}`;
        table.innerHTML = '';               //将table清空，用来重新渲染
        let flag = [];                      //标记每个块是否被访问
        let arr = [];                       //用于广度搜索的数组
        let cubes = [];                     //用来记录每个块的element标签，位置还有是否是炸弹
        let dir = [[1, 0], [0, 1], [-1, 0], [0, - 1], [1, 1], [-1, 1], [-1, -1], [1, -1]];      //定义8个方向，前四个方向是前后左右
        let bomb = [];                      //用来指定那个块是炸弹，为1时将对应的位置元素设置成炸弹
        let flagArr = [];                   //用来记录当前位置是否被插入了旗子
        //初始化
        for (let i = 0; i < n; i++) {
            for (let j = 0; j < n; j++) {
                if (i * n + j < bombNum) {
                    bomb[i * n + j] = 1     //先设置bombNum数的炸弹数
                } else {
                    bomb[i * n + j] = 0
                }
                flagArr[i * n + j] = 0;     //刚开始所有的位置均不插入位置
            }
        }
        //将bomb乱序，实现炸弹随机的效果
        bomb.sort(() => {
            return 0.5 - Math.random();
        })
        //初始化cubes和flag
        for (let i = 0; i < n; i++) {
            flag[i] = [];
            for (j = 0; j < n; j++) {
                cubes[i * n + j] = {
                    x: i,
                    y: j,
                    bomb: bomb[i * n + j]
                };
                flag[i][j] = 0;
            }
        }
        //初始渲染页面
        for (let i = 0; i < n; i++) {
            let tr = document.createElement("tr");
            for (let j = 0; j < n; j++) {
                let td = document.createElement("td");
                td.classList.add("cube");
                td.setAttribute("index", i * n + j);        //给每个td设置一个自定义属性，用来判断当前的td的位置
                cubes[i * n + j].el = td;                   //将td标签压入cubes相应的元素中
                tr.appendChild(td);
            }
            table.appendChild(tr);
        }
        //阻止右键默认弹出菜单栏
        table.addEventListener("contextmenu", (e) => {
            e.preventDefault()
        })
        //失败时的回调
        function fail() {
            let fail = document.querySelector(".refresh");
            fail.style.display = "block";
            fail.innerHTML = "重新开始";
        }
        //成功时的回调
        function success() {
            let fail = document.querySelector(".refresh");
            fail.style.display = "block";
            fail.innerHTML = "成功了！！";
        }
        let flagNum = 0;            //记录插入的旗子数量
        table.addEventListener("mouseup", (e) => {          //这里由于要判断左键还是右键，故用的时mouseup事件（mousedown）也可以
            let el = e.target;                  //el记录当前的点击节点
            if (e.button == 0) {                //e.button 用来判断 0 是左键 1 是中键 2 是右键
                if (el.tagName.toLowerCase() == 'td') {
                    let index = el.getAttribute("index");   //记录当前点击模块的下表
                    if (cubes[index].bomb === 0) {
                        arr.push(cubes[index]);             //当点击的地方不是炸弹时，放入数组中，作为广搜的起点
                        flag[Math.floor(index / n)][parseInt(index % n)] = 1;       //把点击的地方设置成已访问
                        // 这里进行广度搜索
                        while (arr.length != 0) {
                            let num = 0;                    //num用来记录arr[0]对应的节点周围的炸弹数量
                            for (let i = 0; i < 8; i++) {           //判断8个方向
                                let x = arr[0].x + dir[i][0];       //x,y用来记录当前方向下将要走的节点的位置坐标
                                let y = arr[0].y + dir[i][1];
                                /**1.当将要走的节点没有超出边界，并且未被访问，而且还不是炸弹，
                                 * 并且时用过前后左右四个方向可以到达的时候（能到达证明是连通的）
                                 * 将下一个位置设置成已访问，并将其压入arr中，进行接下来的搜索
                                 * 
                                 * 2.若不满足上面的情况，但是满足以下情况
                                 *     即要走的位置是炸弹，就将num++
                                 **/
                                if (x >= 0 && y >= 0 && x < n && y < n && cubes[x * n + y].bomb == 1) {
                                    num++;
                                }
                            }
                            if (num == 0) {
                                for (let i = 0; i < 8; i++) {           //判断8个方向
                                    let x = arr[0].x + dir[i][0];       //x,y用来记录当前方向下将要走的节点的位置坐标
                                    let y = arr[0].y + dir[i][1];
                                    /**1.当将要走的节点没有超出边界，并且未被访问，而且还不是炸弹，
                                     * 并且时用过前后左右四个方向可以到达的时候（能到达证明是连通的）
                                     * 将下一个位置设置成已访问，并将其压入arr中，进行接下来的搜索
                                     * 
                                     * 2.若不满足上面的情况，但是满足以下情况
                                     *     即要走的位置是炸弹，就将num++
                                     **/
                                    if (x >= 0 && y >= 0 && x < n && y < n && flag[x][y] == 0 && cubes[x * n + y].bomb == 0 && i < 4) {
                                        arr.push(cubes[x * n + y]);
                                        flag[x][y] = 1;
                                    }
                                }
                            }
                            /**
                             * 对num进行判断，值为0，1，2，3的时候分别给arr[0]设置zero,one,two,three样式,并且改变对应标签的内容为周围的炸弹数量
                             * 若大于4，直接将设置内容为炸弹数量              
                             */
                            if (num == 0) {
                                arr[0].el.classList.add('zero');
                            } else if (num == 1) {
                                arr[0].el.classList.add('one');
                                arr[0].el.innerHTML = num;
                            } else if (num == 2) {
                                arr[0].el.classList.add('two');
                                arr[0].el.innerHTML = num;
                            } else if (num == 3) {
                                arr[0].el.classList.add('three');
                                arr[0].el.innerHTML = num;
                            } else arr[0].el.innerHTML = num;
                            arr.shift();
                        }
                        let restNum = 0             //用来记录没有被访问的块的数量
                        for (let i = 0; i < n; i++) {
                            for (let j = 0; j < n; j++) {
                                if (!flag[i][j]) {
                                    restNum++;
                                }
                            }
                        }
                        if (restNum + flagNum === bombNum) {    //若未被访问的块的数量加上插上的旗子的数量与炸弹总数相等，则认定为游戏成功
                            success();
                            return;
                        }
                    }
                    else {                              //若点击的块是炸弹，则直接结束游戏
                        cubes[index].el.innerHTML = bomb_html;
                        fail();
                        return;
                    }
                }
            } else if (e.button == 2) {
                let index = el.getAttribute("index");
                /** 这里用来判断右键的情况，插入旗子
                 * 1.若点击的位置是字体图标（即有旗子），则将旗子拔出
                 * 2.若点击的位置是td，没有插上旗子，则将旗子插入
                */
                if (el.tagName.toLowerCase() == 'svg') {
                    index = el.parentNode.getAttribute("index");
                    flagNum--;
                    flagArr[el.parentNode.getAttribute("index")] = 0;       //拔除旗子并且将旗子的flagArr设置为0(为1时就是有旗子)
                    el.parentNode.innerHTML = '';
                    flag[Math.floor(index / n)][parseInt(index % n)] = 0;   //将当前的位置设置成未访问
                }
                else {
                    if (flagArr[el.getAttribute("index")] == 0 && flag[Math.floor(index / n)][parseInt(index % n)] == 0) {
                        flagNum++;
                        flagArr[el.getAttribute("index")] = 1;                 //插上旗子
                        flag[Math.floor(index / n)][parseInt(index % n)] = 1;  //将当前位置设置成已访问
                        el.innerHTML = flag_html;
                    }
                }
                rest.innerHTML = `剩余旗子数：${bombNum - flagNum}`;             //改变剩余旗子数
                /**
                 * 当旗子全部插完时，判断插旗子的位置是不是全是炸弹，若不是则失败，是则成功
                 */
                if (flagNum == bombNum) {
                    let fff = false;
                    for (let i = 0; i < flagArr.length; i++) {
                        if (flagArr[i] != bomb[i]) {
                            fff = true;
                            break;
                        }
                    }
                    if (fff) {
                        fail();
                        return;
                    } else {
                        success();
                        return;
                    }
                }
            }
        });
    }
    /**
     * 1.easy设置成10*10 ，10个雷
     * 2.中等难度 15*15 ， 40个雷（感觉最难，哈哈哈）
     * 3.困难难度 20*20 ， 100个雷
     */
    document.querySelector(".easy").addEventListener("click", (e) => {
        if (document.querySelector(".active")) {
            document.querySelector(".active").classList.remove("active");
        }
        e.target.classList.add("active");
        create(10, 10)
    })
    document.querySelector(".normal").addEventListener("click", (e) => {
        if (document.querySelector(".active")) {
            document.querySelector(".active").classList.remove("active");
        }
        e.target.classList.add("active");
        create(15, 40);
    })
    document.querySelector(".hard").addEventListener("click", (e) => {
        if (document.querySelector(".active")) {
            document.querySelector(".active").classList.remove("active");
        }
        e.target.classList.add("active");
        create(20, 100);
    })
    //给重新开始设定点击事件
    document.querySelector('.refresh').addEventListener('click', () => {
        location.reload();
    })
})